import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

public class CommandExecutor {
	private enum COMMAND_TYPE {
		EXIT,
		ADD,
		REMOVE,
		MODIFY,
		CLEAR,
		SORT,
		SEARCH,
		FINISH,
		DISPLAY,
		UNDO,
		INVALID_COMMAND;
	};
	private static final String COMMAND_TYPE_EXIT = "exit";
	private static final String COMMAND_TYPE_ADD = "add";
	private static final String COMMAND_TYPE_DISPLAY = "display";
	private static final String COMMAND_TYPE_REMOVE = "remove";
	private static final String COMMAND_TYPE_MODIFY = "modify";
	private static final String COMMAND_TYPE_CLEAR = "clear";
	private static final String COMMAND_TYPE_SEARCH = "search";
	private static final String COMMAND_TYPE_SORT = "sort";
	private static final String COMMAND_TYPE_FINISH = "finish";
	private static final String COMMAND_TYPE_UNDO = "undo";
	private static final String ERROR_MESSAGE_COMMAND_TYPE_CANNOT_BE_NULL = "command type string cannot be null!";
	private static final String MESSAGE_INVALID_FORMAT = "Invalid command format :\"%1$s\".";
	private static final String ERROR_MESSAGE_UNRECOGNIZED_COMMAND_TYPE = "Unrecognized command type";
	private FileManager fileManager= new FileManager();
	private MessageManager logicMessageManager = new MessageManager();
	private static ArrayList<Task> virtualStorage = new ArrayList<Task>();
	private static final int INDEX_START = 0;
	private static final int ENUM_SIZE = 11;
	
	public CommandExecutor() {
	
	}
	
	public ArrayList<Task> executeCommand(Command userCommand, ArrayList<Command> commandList) {
		COMMAND_TYPE commandType = determineCommandType(userCommand.getType());
		
		switch (commandType) {
		case ADD :
			return add(userCommand);
		case DISPLAY :
			return display(userCommand);
		case REMOVE :
			return remove(userCommand);
		case CLEAR :
			return clear(userCommand);
		case SORT :
			return sort(userCommand);
		case SEARCH :
			return search(userCommand);
		case UNDO :
			return undo(userCommand);
		case FINISH :
			return finish(userCommand);
		case MODIFY :
			return modify(userCommand);
		case EXIT :
			return exit(userCommand);
		case INVALID_COMMAND :
			logicMessageManager.logicSendMessageToGUI(String.format(MESSAGE_INVALID_FORMAT, userCommand));
			return null;
		default:
			throw new Error(ERROR_MESSAGE_UNRECOGNIZED_COMMAND_TYPE);
		}
	}
	
	
	
	private ArrayList<Task> exit(Command userCommand) {
		// TODO Auto-generated method stub
		return null;
	}

	private ArrayList<Task> modify(Command userCommand) {
		virtualStorage = fileManager.processCommands("READ", null, null, null);
		ArrayList<String> searchContent= retriveSearchContent(userCommand);
		ArrayList<String> modifyContent = retriveModifyContent(userCommand);
		Task result = searchKeyWords(virtualStorage,searchContent).get(INDEX_START);
		virtualStorage=modifyContent(modifyContent,virtualStorage.indexOf(result),virtualStorage);
		fileManager.processCommands("MODIFY", null, null, virtualStorage);
		return virtualStorage;
	}

	

	

	private ArrayList<Task> finish(Command userCommand) {
		ArrayList<String> searchContent = userCommand.getContentForSearch();
		virtualStorage = fileManager.processCommands("READ", null, null, null);
		searchContent.remove(INDEX_START);
		Task result = searchKeyWords(virtualStorage,searchContent).get(INDEX_START);
		result.finishATask();
		virtualStorage.set(virtualStorage.indexOf(result), result);
		fileManager.processCommands("MODIFY", null, null, virtualStorage);
		return virtualStorage;
	}

	private ArrayList<Task> undo(Command userCommand) {
		// TODO Auto-generated method stub
		return null;
	}

	private ArrayList<Task> search(Command userCommand) {
		virtualStorage = fileManager.processCommands("READ", null, null, null);
		//System.out.println(virtualStorage.isEmpty());
		if(userCommand.getContentForSearch().size()<=1) {
			//System.out.println("HI");
			return virtualStorage;
		}
		ArrayList<String> contents = userCommand.getContentForSearch();
		contents.remove(INDEX_START);
		ArrayList<Task> results = searchKeyWords(virtualStorage,contents);
		return results;
	}

	private ArrayList<Task> sort(Command userCommand) {
		if(userCommand.getContentForSearch().size()>1) {
		
		String userInput = userCommand.getContentForSearch().get(1);
		fileManager.processCommands(userCommand.getType(), userInput, null, null);
		}
		return fileManager.processCommands("READ", null, null, null);
	}

	private ArrayList<Task> clear(Command userCommand) {
		virtualStorage.clear();
		fileManager.processCommands(userCommand.getType(), null, null, null);
		return fileManager.processCommands("READ", null, null, null);
	}

	private ArrayList<Task> remove(Command userCommand) {
		ArrayList <Task> objectList = new ArrayList<Task>();
		Task removedTask = new Task(null);
		objectList = fileManager.processCommands("Read", null, null, null);
		ArrayList <String> contents = userCommand.getContentForSearch();
		String removedContent = contents.get(1);
		boolean doneRemoveAlready = false;
		
		try{
			int removedIndex = Integer.parseInt(removedContent);
		}catch(NumberFormatException e){
			String removedEvent = contents.get(1);
			ArrayList<Task> possibleEventList = searchKeyWords(objectList,contents);
			if(possibleEventList.size() == 1) {
				int startIndex = objectList.size() - 1;
				boolean shouldGetOutOfForLoop = false;
			
				for(int arrayIndex = startIndex; arrayIndex >= 0 && (!shouldGetOutOfForLoop); arrayIndex--) {
					if(removedEvent.equals(objectList.get(arrayIndex).getTitle())) {
						removedTask = objectList.remove(arrayIndex);
						shouldGetOutOfForLoop = true;
					}
				}
				
				//pass back to file manager
				fileManager.processCommands("remove", null, removedTask, objectList);
			} else {
				return possibleEventList;
			}
			
			doneRemoveAlready = true;
		}
		
		if(!doneRemoveAlready) {
			int removedIndex = Integer.parseInt(removedContent);
			
			if(removedIndex == 0) {
				logicMessageManager.logicSendMessageToGUI("Remove by index should start from 1.");
			} else if(removedIndex > objectList.size()) {
				logicMessageManager.logicSendMessageToGUI("Do not have such an event");
			} else {
				removedTask = objectList.remove(removedIndex - 1);
			}
			
			//pass back to file manager
			fileManager.processCommands("remove", null, removedTask, objectList);
		}
	
		
		return objectList;
	}

	private ArrayList<Task> display(Command userCommand) {
		virtualStorage = fileManager.processCommands("READ", null, null, null);
		System.out.println(virtualStorage.isEmpty());
		ArrayList<Task> finishedTask = retriveFinishTasks(virtualStorage);
		System.out.println(finishedTask.isEmpty());
		return finishedTask;
	}

	private ArrayList<Task> add(Command userCommand) {
		// TODO Auto-generated method stub
		Task addTask = new Task(userCommand.getContentForSearch());
		if(addTask.isValid()) {
			fileManager.processCommands(userCommand.getType(), null, addTask, null);
		}
		
		return fileManager.processCommands("READ", null, null, null);
	}

	private static COMMAND_TYPE determineCommandType(String commandTypeString) {
		if (commandTypeString == null) {
			throw new Error(ERROR_MESSAGE_COMMAND_TYPE_CANNOT_BE_NULL);
		}

		for(int index= INDEX_START; index<ENUM_SIZE;index++ ) {
			if(COMMAND_TYPE.values()[index].toString().equals(commandTypeString)) {
				return COMMAND_TYPE.values()[index];
			}
		}
		return COMMAND_TYPE.INVALID_COMMAND;
	}
	private static ArrayList<Task> searchKeyWords(ArrayList<Task> virtualStorage,ArrayList<String> contents) {
		int frequency[] = new int[virtualStorage.size()];
		ArrayList<Task> results = new ArrayList<Task>();
		for(int INDEX_IN_CONTENTS = INDEX_START; INDEX_IN_CONTENTS<contents.size();INDEX_IN_CONTENTS++) {
			for(int INDEX_IN_STORAGE = INDEX_START;INDEX_IN_STORAGE<virtualStorage.size();INDEX_IN_STORAGE++) {
				if(virtualStorage.get(INDEX_IN_STORAGE).contains(contents.get(INDEX_IN_CONTENTS))) {
					frequency[INDEX_IN_STORAGE]++;
				}
			}
		}
		for(int INDEX_IN_FREQUENCY=0;INDEX_IN_FREQUENCY<frequency.length;INDEX_IN_FREQUENCY++) {

			int max = -1;
			int index = -1;
			for(int INDEX_OF_FREQUENCY=0;INDEX_OF_FREQUENCY<frequency.length;INDEX_OF_FREQUENCY++) {
				if(frequency[INDEX_OF_FREQUENCY]>max) {
					max = frequency[INDEX_OF_FREQUENCY];
					index = INDEX_OF_FREQUENCY;

				}
			}
			if(max!= 0) {
				results.add(virtualStorage.get(index));
				frequency[index]=0;
			}
		}
		return results;
	}

	private static ArrayList<Task> retriveFinishTasks(ArrayList<Task> virtualStorage) {
		ArrayList<Task> result = new ArrayList<Task>();
		for(int index = INDEX_START;index<virtualStorage.size();index++) {
			if(virtualStorage.get(index).isThisTaskFinished()) {
				result.add(virtualStorage.get(index));
			}
		}
		return result;
	}

	private static ArrayList<String> retriveModifyContent(Command userCommand) {
		ArrayList<String> modifyContent = new ArrayList<String> ();
		ArrayList<String> originalContent = userCommand.getContentForSearch();
		for( int index = originalContent.indexOf("/")+1;index<originalContent.size();index++) {
			modifyContent.add(originalContent.get(index));
		}
		return modifyContent;
	}
	private static ArrayList<String> retriveSearchContent(Command userCommand) {
		ArrayList<String> allContent = userCommand.getContentForSearch();
		ArrayList<String> searchContent = new ArrayList<String>();
		for(int index = 1; index<allContent.indexOf("/")-1;index++) {
			searchContent.add(allContent.get(index));
		}
		
		return searchContent;
	}
	private ArrayList<Task> modifyContent(ArrayList<String> modifyContent, int index, ArrayList<Task> virtualStorage) {
		Task taskToBeModified = virtualStorage.get(index);
		String modifiedTitle = modifyContent.get(0);
		if(!(modifiedTitle.trim().equals(" ")||modifiedTitle.trim().equals(""))) {
			taskToBeModified.modifyName(modifiedTitle);
		}
		String modifiedTime = new String();
		try {
			modifiedTime = modifyContent.get(1);
			try {
				Calendar today = Calendar.getInstance();
				Date theDate = new SimpleDateFormat("MMMM dd yyyy HH:mm", Locale.ENGLISH).parse(modifiedTime);
				Date currentDate = today.getTime();
				if(currentDate.after(theDate)) {
					modifiedTime = "";
				}
				} catch (Exception e) {
					modifiedTime = "";
			}
		} catch (Exception e) {
			modifiedTime = "";
		}
		if(!modifiedTime.equals("")) {
			taskToBeModified.modifyTime(modifiedTime);
		}
		String modifiedTag = new String();
		try {
			modifiedTag = modifyContent.get(2);
		} catch (Exception e) {
			
		}
		taskToBeModified.modifyTag(modifiedTag);
		String modifiedLevel = new String();
		try {
			modifiedLevel = modifyContent.get(3);
			taskToBeModified.modifyUrgencyLevel(modifiedLevel);
		} catch (Exception e) {
		}
		virtualStorage.set(index, taskToBeModified);
		return virtualStorage;
	}
}
